package cs.ubbcluj.ro.algorithm;

import cs.ubbcluj.ro.datatypes.interfaces.Matrix;
import cs.ubbcluj.ro.datatypes.interfaces.Vector;
import cs.ubbcluj.ro.lp.LP;

public class AlgorithmWeighted extends AlgorithmBase {
	
	double theta;

	public AlgorithmWeighted(LP lp, double sigma, double rho, double epsilon, double theta) {
		super(lp, sigma, rho, epsilon, theta);
		
		this.theta = theta;
	}
	
	/**
	 * instead of nu, calculate the value of w^2 - x * s
	 * uses the same function name, so the abstraction can be done in a simpler way
	 * @return Vector
	 * @throws InterruptedException
	 */
	public Vector calculateRightHandSide(boolean useSuperClass) throws InterruptedException {
		
		if (useSuperClass) {
			return super.calculateRightHandSide(useSuperClass);
		} else {
			// calculate the value of x * s and store it in a temporary array
			Vector xs = lp.getX().createHelperVector(lp.getXLength());
			xs.set(lp.getX());
			xs.productScalar(lp.getS());
			
			// calculate w ^ 2		
			Vector resultVector = lp.getW().createHelperVector(lp.getW().getNrOfRows());
			resultVector.set(lp.getW());
			resultVector.productScalar(lp.getW());
			
			// calculate w ^ 2 - x * s
			resultVector.set(resultVector.diff(xs));				
			
			return resultVector;
		}
	}
	
	public double centralityDegree(Vector w) {
		System.out.println(w.max() + " " + w.min());
		return w.max() / w.min();
	}
	
    /**
     * sets the value of w given by the formula w = (1 - theta) * w
     * @throws InterruptedException 
     */
    Vector getWFromPreviousW(Vector v) throws InterruptedException {
    	Vector w = v.createHelperVector(v.getNrOfRows());
    	w.set(v);
    	w.product(1-theta);
    	return w;
    }
    
    /**
     * sets the value of the w given by the formula w = sqrt(x * s)
     * @throws InterruptedException
     */
    Vector getWFromSqrtXS() throws InterruptedException {
    	Vector xs = lp.getX().createHelperVector(lp.getXLength());
		xs.set(lp.getX());
		xs.productScalar(lp.getS());
		xs.sqrt();	
		
		return xs;
    }
    
	
    /**
     * sets the optimal W
     */
	public void setW() throws InterruptedException {
		lp.setW(getWFromPreviousW(lp.getW()));
		/*Vector xs = getWFromSqrtXS();
		
		if (lp.getW().min() > epsilon && centralityDegree(xs) < centralityDegree(lp.getW())) {
			System.out.println("------------- using XS");			
			lp.setW(getWFromPreviousW(xs));		
		} else {
			System.out.println("------------- using W");
			lp.setW(getWFromPreviousW(lp.getW()));
		}*/
	}
	/**
	 * solves problem 
	 * @throws InterruptedException
	 */
	public void solveProblem() throws InterruptedException {	
		int iterationCount = 0;
		
		do {			
			setW();
			
			// get value of nu
			nu = calculateRightHandSide(false);
				
			// calculate the value of rb		
			rb = lp.getRb();
			
			// calculate the value of rc
			rc = lp.getRc();

			// calculate AXS^-1
			Matrix AXS_1 = lp.getAXS_1();
			
			// calculate AS^-1
			Matrix AS_1 = lp.getAS_1();
			
			// calculate deltaY
			Matrix AD2At = lp.getAD2At();			
			deltaY = getDeltaY(AD2At, AXS_1, AS_1);
			
			// calculate deltaS
			deltaS = getDeltaS();
			
			// calculates deltaX
			deltaX = getDeltaX();
			
			// calculates alphaPrimal
			alphaPrimal = min(lp.getX(), deltaX);
			
			// calculates alphaDual
			alphaDual = min(lp.getS(), deltaS);

			// set values for x, y, s
			setX();
			setY();
			setS();
			
			iterationCount++;

			System.out.println("----------------------------");
			System.out.println("Primal = " + lp.getPrimal());
			System.out.println("Dual= " + lp.getDual());
			System.out.println("iteration = " + iterationCount);
			
		} while (!isResultGoodEnough() && iterationCount < 50);		
		
		System.out.println("\niterationCount = " + iterationCount);
	}
}
